iT邦幫忙

2024 iThome 鐵人賽

DAY 23
0
佛心分享-SideProject30

從卡關到通關的Spring Boot 腦內風暴系列 第 23

全場我Hand住-@ControllerAdvice 與 ExceptionHandler

  • 分享至 

  • xImage
  •  

延續前一篇,此篇針對全局異常處理進一步說明。因為在程式規模變大之際,異常處理會隨之複雜,若是在各自的控制器處理錯誤,會使得程式碼越來越冗贅且難以維護。透過Spring的@ControllerAdvice以及@ExceptionHandler可以更好將異常處理集中管理,提高維護性及可讀性。

@ControllerAdvice 作用

@ControllerAdvice是Spring提供的功能,定義全局異常處理器,可以自動攔截所有API控制器的異常。通常與@ExceptionHandler一起使用,可以指定處理特定異常錯誤類型。

@ExceptionHandler 作用

@ExceptionHandler是用來指定處理特定異常,可與@ControllerAdvice搭配用於全局控制,或是單獨用於一個控制器當中。

實際應用

  • 有時候遇到特定業務邏輯的異常,可以建立自定義異常,結合全局異常來統一處理此錯誤。
// 建立自定義異常
@ResponseStatus(HttpStatus.BAD_REQUEST)
public class OrderBadRequestException extends RuntimeException {
    public OrderBadRequestException(String message) {
        super(message);
    }
}

// 定義全局異常控制器
@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(OrderBadRequestException.class) // 自定義的特定異常處理
    public ResponseEntity<Object> handleOrderBadRequest(OrderBadRequestException ex) {
        Map<String, Object> body = new HashMap<>();
        body.put("status", HttpStatus.BAD_REQUEST.value());
        body.put("error", "Bad Request");
        body.put("message", ex.getMessage());
        return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
    }
    
    @ExceptionHandler(Exception.class)     // 通用異常處理
    public ResponseEntity<Object> handleGlobalException (Exception ex) {   
        Map<String, Object> body = new HashMap<>();
        body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
        body.put("error", "Internal Server Error");
        body.put("message", "wrong");
        return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}
  • 處理單個控制器異常,可直接使用@ExceptionHandler:
@RestController
public class MemberController {

    @GetMapping("/member")
    public String member() {
        throw new MemberBadRequestException("This is a bad request");
    }
    
    @ExceptionHandler(MemberBadRequestException.class)
    public ResponseEntity<Object> handleMemberBadRequest(MemberBadRequestException ex) {    
        Map<String, Object> body = new HashMap<>();
        body.put("error", "Bad Request");
        body.put("message", ex.getMessage());
        return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);    
    }
}
  • @ControllerAdvice除了能全局控制,也能指定處理某些控制器:
// 只處理 com.num.controller 底下的控制器
@ControllerAdvice(basePackages = "com.num.controller")
public class PackageSpecificExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleGlobalException(Exception ex) {
        Map<String, Object> body = new HashMap<>();
        body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
        body.put("error", "Internal Server Error");
        body.put("message", ex.getMessage());
        return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

// 只處理 MyController 和 AnotherController 異常
@ControllerAdvice(assignableTypes = {MyController.class, AnotherController.class})
public class SpecificControllerExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<Object> handleGlobalException(Exception ex) {
        Map<String, Object> body = new HashMap<>();
        body.put("status", HttpStatus.INTERNAL_SERVER_ERROR.value());
        body.put("error", "Internal Server Error");
        body.put("message", ex.getMessage());
        return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

綜合上述,善用全局異常處理,可以避免程式碼重寫,並且增加可讀性,提升維護性,更重要的是,也能更好與前端協作。


上一篇
錯誤也能優雅設計-選擇正確的 HTTP 狀態碼
下一篇
分頁與排序的藝術-Pageable及Sort的實踐
系列文
從卡關到通關的Spring Boot 腦內風暴30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言